<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
    <meta content='width=device-width, initial-scale=1.0' name='viewport'>
    <meta content='' name='description'>
    <meta content='Nils Nordman' name='author'>
    <link href='/images/howl.png' rel='shortcut icon'>
    <title>Howl :: howl.bindings</title>
    <link href="/stylesheets/bootstrap.min.css" media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/syntax.css" media="screen" rel="stylesheet" type="text/css" />
    <link href="/stylesheets/howl.css" media="screen" rel="stylesheet" type="text/css" />
    <link href='//fonts.googleapis.com/css?family=Josefin+Slab' rel='stylesheet' type='text/css'>
    <link href='//fonts.googleapis.com/css?family=Open+Sans+Condensed:700' rel='stylesheet' type='text/css'>
  </head>
  <body class='doc doc_api doc_api_bindings'>
    <div class='container'>
      <div class='masthead'>
        <ul class='nav nav-pills'>
          <li>
            <a href='/'>
              <span class='glyphicon glyphicon-home'></span>
              Home
            </a>
          </li>
          <li>
            <a href='/doc/'>
              <span class='glyphicon glyphicon-book'></span>
              Documentation
            </a>
          </li>
          <li>
            <a href='/blog/'>
              <span class='glyphicon glyphicon-bullhorn'></span>
              Blog
            </a>
          </li>
          <li>
            <a href='/contact.html'>
              <span class='glyphicon glyphicon-inbox'></span>
              Contact
            </a>
          </li>
        </ul>
      </div>
      <ol class="breadcrumb"><li><a href="/">Home</a></li><li><a href='../'>Howl 0.3 Documentation</a></li><li>Api</li><li>howl.bindings</li></ol>
      <h1 id="howl.bindings">howl.bindings</h1>    <div class="toc">
      <div class="toc-title">
        <span>howl.bindings</span>
      </div>
      <div class="toc-entries">
<div class="toc-group">
<a href="#overview" class="toc-group-header overview">Overview</a>
<li class=""><a href="#indirect-bindings">Indirect bindings</a></li>
</div>
<div class="toc-group">
<a href="#properties" class="toc-group-header properties">Properties</a>
<li class=""><a href="#.is_capturing">.is_capturing</a></li>
<li class=""><a href="#.keymaps">.keymaps</a></li>
</div>
<div class="toc-group">
<a href="#functions" class="toc-group-header functions">Functions</a>
<li class=""><a href="#action_for">action_for </a></li>
<li class=""><a href="#cancel_capture">cancel_capture </a></li>
<li class=""><a href="#capture">capture </a></li>
<li class=""><a href="#dispatch">dispatch </a></li>
<li class=""><a href="#keystrokes_for">keystrokes_for </a></li>
<li class=""><a href="#pop">pop </a></li>
<li class=""><a href="#process">process </a></li>
<li class=""><a href="#push">push </a></li>
<li class=""><a href="#remove">remove </a></li>
<li class=""><a href="#translate_key">translate_key </a></li>
</div>
</div>
</div>
&#x000A;&#x000A;<h2 id="overview">Overview</h2>&#x000A;&#x000A;<p>howl.bindings handles the set of active key bindings within Howl. &ldquo;Bindings&rdquo; in&#x000A;this context refers to the various actions that will be executed as the result of&#x000A;a key press, and we say that a key is bound to a certain action whenever that action&#x000A;will trigger as a result of the key being pressed.</p>&#x000A;&#x000A;<p>The way this works in Howl is that bindings keeps track of an arbitrary number&#x000A;of &ldquo;keymaps&rdquo; that are searched whenever a key is pressed. A keymap is simple a&#x000A;Lua table with keys matching key translations. The keymaps are stacked, and they&#x000A;will all be searched for a matching action whenever a key is pressed. Typically&#x000A;processing stops whenever the first action has been triggered, but it&rsquo;s possible&#x000A;for a handler to allow a key press to propagate further down the stack if it so&#x000A;chooses.</p>&#x000A;&#x000A;<p>Keymaps are as said simple Lua tables, that maps &ldquo;key translations&rdquo; to actions.&#x000A;Each key press is represented as a &ldquo;key event&rdquo;, which is also a simple Lua table.&#x000A;Below you can see an example of a key event resulting from pressing&#x000A;<code>Control + Shift + a</code>:</p>&#x000A;<pre class="highlight lua"><span class="c1">-- Key event</span>&#x000A;<span class="p">{</span>&#x000A;  <span class="n">character</span> <span class="o">=</span> <span class="s2">"A"</span><span class="p">,</span> <span class="c1">-- the character corresponding to the key press, if any</span>&#x000A;  <span class="n">key_code</span> <span class="o">=</span> <span class="mi">65</span><span class="p">,</span>   <span class="c1">-- the code of the key pressed</span>&#x000A;  <span class="n">key_name</span> <span class="o">=</span> <span class="s2">"a"</span><span class="p">,</span>  <span class="c1">-- a symbolic name for the key pressed, if any</span>&#x000A;  <span class="n">alt</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span>     <span class="c1">-- true if the alt key was held down during the key press</span>&#x000A;  <span class="n">control</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>  <span class="c1">-- true if the control key was held down during the key press</span>&#x000A;  <span class="n">meta</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span>    <span class="c1">-- true if the meta key was held down during the key press</span>&#x000A;  <span class="n">shift</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>    <span class="c1">-- true if the shift key was held down during the key press</span>&#x000A;  <span class="n">super</span> <span class="o">=</span> <span class="kc">false</span>    <span class="c1">-- true if the super key was held down during the key press</span>&#x000A;<span class="p">}</span>&#x000A;</pre>&#x000A;<p>As part of <a href="#process">processing</a> the key event is translated to a list of&#x000A;possible string representations using <a href="#translate_key">translate_key</a>, which&#x000A;for the above example would result in the following list of translations:</p>&#x000A;<pre class="highlight lua"><span class="p">{</span>&#x000A;  <span class="s2">"ctrl_A"</span><span class="p">,</span>&#x000A;  <span class="s2">"ctrl_shift_a"</span><span class="p">,</span>&#x000A;  <span class="s2">"ctrl_shift_65"</span>&#x000A;<span class="p">}</span>&#x000A;</pre>&#x000A;<p>All keymaps are then searched in order for keys matching any of the translations.&#x000A;If you read the documentation for <a href="#process">process</a> you&rsquo;ll see that all key&#x000A;events are processed for a particular originating source. In the typical case&#x000A;this will be &ldquo;editor&rdquo;, indicating the key press originated from an&#x000A;<a href="ui/editor.html">editor</a>. When searching keymaps, any keymap is first inspected&#x000A;to see if it has a source specific keymap table, in which case this is searched&#x000A;first before any top-level bindings. Consider the following keymap:</p>&#x000A;<pre class="highlight lua"><span class="p">{</span>&#x000A;  <span class="n">ctrl_b</span> <span class="o">=</span> <span class="k">function</span><span class="p">()</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"A general binding"</span><span class="p">)</span> <span class="k">end</span><span class="p">,</span>&#x000A;  <span class="n">ctrl_c</span> <span class="o">=</span> <span class="s1">'my_general_command'</span><span class="p">,</span>&#x000A;&#x000A;  <span class="n">editor</span> <span class="o">=</span> <span class="p">{</span>&#x000A;    <span class="n">ctrl_shift_a</span> <span class="o">=</span> <span class="k">function</span><span class="p">(</span><span class="n">editor</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"An editor binding"</span><span class="p">)</span> <span class="k">end</span>&#x000A;  <span class="p">}</span>&#x000A;<span class="p">}</span>&#x000A;</pre>&#x000A;<p>Should the key event example above be dispatched against this keymap with the&#x000A;source being &ldquo;editor&rdquo;, it would trigger the &ldquo;ctrl_shift_a&rdquo; binding. The top-level&#x000A;bindings (e.g. &ldquo;ctrl_b&rdquo;) would trigger regardless of source. Also note that&#x000A;the editor specific binding can make use of a source specific extra argument,&#x000A;an editor instance in this case.</p>&#x000A;&#x000A;<p>Any matching value found in a keymap is considered an action. Should a keymap not have any&#x000A;matching keys but have a callable field named <code>on_unhandled</code>, that is&#x000A;invoked with the key event, event source, key translations and any extra parameters&#x000A;passed to <a href="#dispatch">dispatch</a>, and any truthy result is used as the action.&#x000A;See the documentation for dispatch for further information about these parameters.</p>&#x000A;&#x000A;<p>Actions can be one of three different things:</p>&#x000A;&#x000A;<ul>&#x000A;<li><p>It can be a string, in which case it&rsquo;s considered a command and will be dispatched&#x000A;using <a href="command.html#run">command.run</a>.</p></li>&#x000A;<li><p>It can be a callable object (a function or table providing a meta-table __call), in&#x000A;which case it&rsquo;s invoked with any extra parameters passed to <a href="#dispatch">dispatch</a>&#x000A;(the typical case being the editor instance for which the key press originated).&#x000A;The key event will be considered handled unless the handler returns false.</p></li>&#x000A;<li><p>It can be an ordinary, non-callable, table. This table is interpreted as an additional&#x000A;keymap, which will be <a href="#push">pushed</a> using the <code>pop</code> option.</p></li>&#x000A;</ul>&#x000A;&#x000A;<h3 id="indirect-bindings">Indirect bindings</h3>&#x000A;&#x000A;<p>When writing keymaps for non-editor sources, a special key called <code>binding_for</code>&#x000A;can be used in the keymap to bind an action to a key press indirectly by using a&#x000A;command name as the key. For example, if you wanted to support <em>pasting</em> in your&#x000A;readline input, instead of binding the action directly to the <code>ctrl_v</code> key&#x000A;press, you might want to bind whichever key is bound to the <code>editor-paste</code>&#x000A;command. This can be specified by the following keymap:</p>&#x000A;<pre class="highlight lua"><span class="p">{</span>&#x000A;  <span class="n">binding_for</span> <span class="o">=</span> <span class="p">{</span>&#x000A;    <span class="p">[</span><span class="s1">'editor-paste'</span><span class="p">]:</span> <span class="k">function</span><span class="p">()</span> <span class="o">...</span> <span class="k">end</span>&#x000A;  <span class="p">}</span>&#x000A;<span class="p">}</span>&#x000A;</pre>&#x000A;<p>This ensures that if the user binds a new key press to the <code>editor-paste</code>&#x000A;command, that new key press will now trigger the bound action above, providing a&#x000A;better experience for the user.</p>&#x000A;&#x000A;<p><em>Protip</em>:</p>&#x000A;&#x000A;<p>You can use the <code>describe-key</code> command to interactively view information for any&#x000A;particular key press, i.e. the key event and translations.</p>&#x000A;&#x000A;<p><em>See also</em>:</p>&#x000A;&#x000A;<ul>&#x000A;<li>The <a href="../spec/bindings_spec.html">spec</a> for howl.bindings</li>&#x000A;</ul>&#x000A;&#x000A;<h2 id="properties">Properties</h2>&#x000A;&#x000A;<h3 id=".is_capturing">.is_capturing</h3>&#x000A;&#x000A;<p>True if there&rsquo;s currently a capture handler installed, and false otherwise.</p>&#x000A;&#x000A;<h3 id=".keymaps">.keymaps</h3>&#x000A;&#x000A;<p>This is a list of the currently active keymaps. This is a stack, with latter keymaps taking precedence over earlier ones.</p>&#x000A;&#x000A;<h2 id="functions">Functions</h2>&#x000A;&#x000A;<h3 id="action_for">action_for <span class="arg-list">(translation)</span></h3>&#x000A;&#x000A;<p>Searches the stack of kemaps for the given key translation and returns the first&#x000A;bound action found. An action may be a string (i.e. a command name) or a&#x000A;function object. If no binding can be found for the translation, <code>nil</code> is&#x000A;returned.</p>&#x000A;&#x000A;<h3 id="cancel_capture">cancel_capture <span class="arg-list">()</span></h3>&#x000A;&#x000A;<p>Removes any installed capture handler.</p>&#x000A;&#x000A;<h3 id="capture">capture <span class="arg-list">(handler)</span></h3>&#x000A;&#x000A;<p>Installs a capture handler. The handler, which should be callable, will&#x000A;intercept any key events being sent to <a href="#process">process</a> for processing. It&#x000A;will be invoked with the key event, source, key translations and any extra&#x000A;parameters passed to process. Unless the handler returns <code>false</code>, it will&#x000A;automatically be removed after the invocation. There can be only one capture&#x000A;handler installed at any given time. Installing a capture handler when an&#x000A;existing one is already set will simply override the previous one.</p>&#x000A;&#x000A;<h3 id="dispatch">dispatch <span class="arg-list">(key_event, source, keymaps, &hellip;)</span></h3>&#x000A;&#x000A;<p>Explicitly dispatches the key event against the specified list of keymaps.&#x000A;<code>source</code> is the source of the key press, e.g. &ldquo;editor&rdquo;. <code>keymaps</code> is the&#x000A;list of keymaps that will be searched. Any additional arguments are passed&#x000A;as is to any callable actions.</p>&#x000A;&#x000A;<p><em>Note</em>:</p>&#x000A;&#x000A;<p>Unlike <a href="#process">process</a>, dispatch will not automatically include any of the&#x000A;keymaps in the binding stack, it will only search <code>keymaps</code>.</p>&#x000A;&#x000A;<h3 id="keystrokes_for">keystrokes_for <span class="arg-list">(action, source)</span></h3>&#x000A;&#x000A;<p>Finds all keystrokes (i.e. translations) that are bound to the specified&#x000A;<code>action</code>. <code>source</code>, if given, specifies the source specific keymaps to search as&#x000A;well. Returns a table containing all keystrokes found, or an empty table if no&#x000A;binding was found.</p>&#x000A;&#x000A;<p>For example:</p>&#x000A;<pre class="highlight lua"><span class="c1">-- look up the binding for the `project-open` command:</span>&#x000A;<span class="n">howl</span><span class="p">.</span><span class="n">bindings</span><span class="p">.</span><span class="n">keystrokes_for</span><span class="p">(</span><span class="s1">'project-open'</span><span class="p">)</span>&#x000A;<span class="c1">-- =&gt; { 'ctrl_p' }</span>&#x000A;&#x000A;<span class="c1">-- look up the binding for the `buffer-search-forward` command:</span>&#x000A;<span class="n">howl</span><span class="p">.</span><span class="n">bindings</span><span class="p">.</span><span class="n">keystrokes_for</span><span class="p">(</span><span class="s1">'buffer-search-forward'</span><span class="p">,</span> <span class="s1">'editor'</span><span class="p">)</span>&#x000A;<span class="c1">-- =&gt; { 'ctrl_f' }</span>&#x000A;&#x000A;<span class="c1">-- but since that's a command only bound for editor sources,</span>&#x000A;<span class="c1">-- it's not bound globally</span>&#x000A;<span class="n">howl</span><span class="p">.</span><span class="n">bindings</span><span class="p">.</span><span class="n">keystrokes_for</span><span class="p">(</span><span class="s1">'buffer-search-forward'</span><span class="p">)</span>&#x000A;<span class="c1">-- =&gt; {}</span>&#x000A;</pre>&#x000A;<h3 id="pop">pop <span class="arg-list">()</span></h3>&#x000A;&#x000A;<p>Pops the top-most keymap of the stack. Raises an error if the stack is empty.</p>&#x000A;&#x000A;<h3 id="process">process <span class="arg-list">(key_event, source, extra_keymaps = {},  &hellip;)</span></h3>&#x000A;&#x000A;<p>Processes the <code>key_event</code> by dispatching it against the list of keymaps present&#x000A;in the bindings stack. <code>source</code> is the source of the key press, e.g. &ldquo;editor&rdquo;.&#x000A;<code>extra_keymaps</code> is an optional list of additional keymaps that will be searched;&#x000A;if specified these will be searched in order before any of the keymaps in the&#x000A;stack. Any additional arguments are passed as is to any callable&#x000A;actions.</p>&#x000A;&#x000A;<p>Should any capture handler be installed via <a href="#capture">capture</a>, this will be&#x000A;invoked first and further processing will be skipped.</p>&#x000A;&#x000A;<p>The <code>key-press</code> signal is emitted before dispatching, and further processing&#x000A;will be skipped if this is handled.</p>&#x000A;&#x000A;<h3 id="push">push <span class="arg-list">(keymap, options = {})</span></h3>&#x000A;&#x000A;<p>Pushes <code>keymap</code> onto the bindings stack. <code>options</code> can contain any of the following keys:</p>&#x000A;&#x000A;<ul>&#x000A;<li><p><em>block</em>: When set to true, this prevents any keymaps lower in the stack to be searched for&#x000A;matching actions, effectively making this the only keymap available.</p></li>&#x000A;<li><p><em>pop</em>: When set to true, this causes the keymap to be popped from the stack automatically&#x000A;after the next key dispatch. If pop is set, the map is implicitly blocking as&#x000A;well.</p></li>&#x000A;</ul>&#x000A;&#x000A;<h3 id="remove">remove <span class="arg-list">(keymap)</span></h3>&#x000A;&#x000A;<p>Removes the specified keymap from the stack. Returns true if the keymap was removed successfully and false if it was not found.</p>&#x000A;&#x000A;<h3 id="translate_key">translate_key <span class="arg-list">(event)</span></h3>&#x000A;&#x000A;<p>Returns a list of translations for the passed in key event.</p>&#x000A;&#x000A;<p>Example (Lua):</p>&#x000A;<pre class="highlight lua"><span class="c1">-- Given the following key event</span>&#x000A;<span class="kd">local</span> <span class="n">key_event</span> <span class="o">=</span> <span class="p">{</span>&#x000A;  <span class="n">alt</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span>&#x000A;  <span class="n">character</span> <span class="o">=</span> <span class="s2">"A"</span><span class="p">,</span>&#x000A;  <span class="n">control</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>&#x000A;  <span class="n">key_code</span> <span class="o">=</span> <span class="mi">65</span><span class="p">,</span>&#x000A;  <span class="n">key_name</span> <span class="o">=</span> <span class="s2">"a"</span><span class="p">,</span>&#x000A;  <span class="n">meta</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span>&#x000A;  <span class="n">shift</span> <span class="o">=</span> <span class="kc">true</span><span class="p">,</span>&#x000A;  <span class="n">super</span> <span class="o">=</span> <span class="kc">false</span>&#x000A;<span class="p">}</span>&#x000A;&#x000A;<span class="n">bindings</span><span class="p">.</span><span class="n">translate_key</span><span class="p">(</span><span class="n">key_event</span><span class="p">)</span>&#x000A;<span class="c1">-- returns</span>&#x000A;<span class="p">{</span>&#x000A;  <span class="s2">"ctrl_A"</span><span class="p">,</span>&#x000A;  <span class="s2">"ctrl_shift_a"</span><span class="p">,</span>&#x000A;  <span class="s2">"ctrl_shift_65"</span>&#x000A;<span class="p">}</span>&#x000A;</pre>
      <div class='footer text-muted'>
        <a href='/'>
          <img width="50" height="50" class="footer-logo" src="/images/howl.png" />
        </a>
        <div class='footer-follow'>
          <p>
            <a class='twitter-follow-button' data-lang='en' data-show-count='false' href='https://twitter.com/howleditor' rel='me'>
              Follow @howleditor
            </a>
          </p>
          <p>
            <a class='twitter-share-button' data-count='none' data-hashtags='howleditor' data-lang='en' data-text='The Howl Editor, a general purpose, light-weight customizable editor.' data-url='http://howl.io' href='https://twitter.com/share'>
              Tweet
            </a>
          </p>
        </div>
        <div class='footer-blurb'>
          <div>The Howl editor.</div>
          <div>
            Copyright 2012-2015
            <a class='alert-link' href='https://github.com/nilnor/howl/contributors'>
              The Howl Developers.
            </a>
          </div>
        </div>
      </div>
    </div>
    <script>
      <!-- / GA -->
      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
      (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
      ga('create', 'UA-45283282-1', 'howl.io');
      ga('send', 'pageview');
      <!-- / Twitter -->
      !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];
      if(!d.getElementById(id)){js=d.createElement(s);js.id=id;
      js.src="//platform.twitter.com/widgets.js";
      fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");
    </script>
  </body>
</html>
